package com.sinosoft.hydra.um.services;

import cn.com.sinux.spring.utils.DateUtils;
import cn.com.sinux.spring.commons.SystemConfig;
import cn.com.sinux.spring.utils.SpecificationHelper;
import cn.com.sinux.spring.utils.ValidatorUtils;
import com.sinosoft.hydra.um.condition.SearchLogCondition;
import com.sinosoft.hydra.um.dao.SysLogInfoDao;
import com.sinosoft.hydra.um.domain.permission.SysLogErrorMessage;
import com.sinosoft.hydra.um.domain.permission.SysLogInfo;
import com.sinosoft.hydra.um.domain.permission.SysLogPackage;
import com.sinosoft.hydra.um.domain.permission.SysLogProperty;
import cn.com.sinux.spring.exception.BusinessException;
import com.sinosoft.hydra.um.helper.LoggerHelper;
import com.sinosoft.hydra.um.repositories.SysLogErrorMessageRepository;
import com.sinosoft.hydra.um.repositories.SysLogInfoRepository;
import com.sinosoft.hydra.um.repositories.SysLogPackageRepository;
import com.sinosoft.hydra.um.repositories.SysLogPropertyRepository;
import com.sinosoft.hydra.um.utils.*;
import com.sinosoft.hydra.um.vo.LogVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 日志消息业务层，负责完成日志列表的功能
 *
 * @author zhengt
 */
@Service
public class SysLogInfoService {

    /**
     * 日志消息数据层
     */
    @Autowired
    private SysLogInfoRepository sysLogInfoRepository;
    @Autowired
    private SysLogPropertyRepository sysLogPropertyRepository;
    @Autowired
    private SysLogErrorMessageRepository sysLogErrorMessageRepository;
    @Autowired
    private FileService fileService;
    /**
     * 错误日志信息业务层
     */
    @Autowired
    private SysLogErrorMessageService sysLogErrorMessageService;
    /**
     * 日志操作者业务层
     */
    @Autowired
    private SysLogPropertyService sysLogPropertyService;
    /**
     * 日志消息包数据层
     */
    @Autowired
    private SysLogPackageRepository sysLogPackageRepository;
    /**
     * 日志报表数据层
     */
    @Autowired
    private SysLogInfoDao sysLogInfoDao;

    /**
     * 查询日志的所有信息
     *
     * @param id 日志id
     * @return 包含了日志信息，日志操作者信息，日志错误信息
     */

    public LogVo findOne(String id) {
        SysLogInfo info = sysLogInfoRepository.findOne(id);
        LogVo log = new LogVo();

        if (info != null) {
            log.setFile(info.getFile());
            log.setMethod(info.getMethod());
            log.setEntityClass(info.getEntityClass());
            log.setLine(info.getLine());
            SysLogProperty logProperty = sysLogPropertyService.findByLogInfo(id);
            if (logProperty != null) {
                log.setIp(logProperty.getIp());
                log.setName(logProperty.getName());
            }
            List<SysLogErrorMessage> li = sysLogErrorMessageService.findByLogInfo(id);
            String msg = "";
            log.setFormsg(info.getMsg());
            if (li != null && li.size() > 0) {
                for (SysLogErrorMessage logMsg : li) {
                    msg += logMsg.getMsg();
                }
                log.setMsg(msg);
            }

        }
        return log;
    }

    /**
     * 分页查询日志信息
     *
     * @param page 分页信息
     * @param t    日志对象
     * @return 返回查询日志信息的List
     */

    public Page<SysLogInfo> findAllByPage(Pageable page, final SearchLogCondition t) {
        return sysLogInfoRepository.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<SysLogInfo>() {

            public void fillParam(Root<SysLogInfo> root, CriteriaBuilder cb, List<Predicate> list) {
                if (StringUtils.isNotBlank(t.getLevel())) {
                    Predicate P_level = cb.equal(root.get("level").as(String.class), t.getLevel());
                    list.add(P_level);
                }
                if (t.getBeginDate() != null) {
                    list.add(cb.greaterThanOrEqualTo(root.get("createDate").as(Date.class), DateUtils.getStartOfDay(t.getBeginDate())));
                }
                if (t.getEndDate() != null) {
                    list.add(cb.lessThanOrEqualTo(root.get("createDate").as(Date.class), DateUtils.getEndOfDay(t.getEndDate())));
                }
            }
        }), page);
    }

    /**
     * 根据id的list查询日志信息
     *
     * @param ids 日志id列表json格式
     * @return 返回日志内容的List
     */

    public List<SysLogInfo> queryPage(List<String> ids) {
        return sysLogInfoRepository.queryPage(ids);
    }

    /**
     * 删除日志信息
     *
     * @param ids 日志id列表json格式
     * @return 操作结果
     */
    @Transactional
    public List<SysLogInfo> delete(List<String> ids) {
        List<SysLogInfo> logInfos = sysLogInfoRepository.findAll(ids);
        sysLogErrorMessageService.deleteFromInfo(ids);
        sysLogPropertyService.deleteFromInfo(ids);
        sysLogInfoRepository.deleteLi(ids);
        return logInfos;
    }

    /**
     * 打包日志信息
     *
     * @param ids 日志id列表json格式
     * @return 返回操作结果
     * @throws java.io.IOException 数据读写异常
     */
    @Transactional
    public List<SysLogPackage> packages(List<String> ids, boolean all) {
        if (!all && ValidatorUtils.isArrayEmpty(ids)) {
            throw new BusinessException("未选择打包的日志项，不能打包失败");
        }
        List<SysLogInfo> li = all ? sysLogInfoRepository.findAll() : sysLogInfoRepository.queryPage(ids);
        List<SysLogPackage> logPackages = new ArrayList<SysLogPackage>();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = format.format(new Date());
        date = date.split(" ")[0] + date.split(" ")[1];
        date = date.split("-")[0] + date.split("-")[1] + date.split("-")[2];
        date = date.split(":")[0] + date.split(":")[1] + date.split(":")[2];

        String relativePath = fileService.getRelativePath();
        String randomDir = fileService.createDir(relativePath);
        List<String> fileString = new ArrayList<String>();
        int pakageSize = SystemConfig.getIntegerProperty("log.package.size", 50);
        int total = li.size();
        try {
            if (total > 0) {
                int dute = total % pakageSize, l = total / pakageSize + (dute > 0 ? 1 : 0);
                for (int i = 0; i < l; i++) {
                    int start = i * 50, end = start + 50;
                    String fileName = relativePath + "/" + randomDir + date + i + ".log";
                    fileString.add(fileName);
                    FileWriter fileWriter = new FileWriter(fileName);
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int j = start; j < (end < total ? end : total); j++) {
                        SysLogInfo info = li.get(j);
                        SysLogProperty sysLogProperty = sysLogPropertyService.findByLogInfo(info.getId());
                        stringBuilder.append(info.toString());
                        if (sysLogProperty != null) {
                            stringBuilder.append(sysLogProperty.toString());
                        }
                        List<SysLogErrorMessage> msgli = sysLogErrorMessageService.findByLogInfo(info.getId());
                        if (ValidatorUtils.isArrayNotEmpty(msgli)) {
                            stringBuilder.append(msgli.toString());
                        }
                        fileWriter.write(stringBuilder.toString() + "\n");
                    }
                    fileWriter.flush();
                    fileWriter.close();
                }
            }

            byte[] buffer = new byte[1024];
            //生成的ZIP文件名为Demo.zip
            String strZipName = relativePath + randomDir + date + ".zip";
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(strZipName));
            //需要同时下载的两个文件result.txt ，source.txt
            if (ValidatorUtils.isArrayNotEmpty(fileString)) {
                for (String aFileString : fileString) {
                    File file = new File(aFileString);
                    FileInputStream fis = new FileInputStream(file);
                    out.putNextEntry(new ZipEntry(file.getName()));
                    int len;
                    //读入需要下载的文件的内容，打包到zip文件
                    while ((len = fis.read(buffer)) > 0) {
                        out.write(buffer, 0, len);
                    }
                    out.closeEntry();
                    fis.close();
                    file.delete();
                }
            }
            out.close();
            SysLogPackage pa = new SysLogPackage();
            pa.setCreateDate(new Date());
            pa.setItemsNum(total + "");
            pa.setPackageName(date);
            pa.setLogFile(randomDir + date + ".zip");
            sysLogPackageRepository.save(pa);
            logPackages.add(pa);
        } catch (Exception e) {
            LoggerHelper.logError("日志打包出错{}", e.getMessage());
            throw new BusinessException("日志打包出错");
        }
        return logPackages;
    }

    /**
     * 查询饼状图数据
     *
     * @param begin   开始时间
     * @param endDate 结束时间
     * @return 返回饼状图结果
     */

    public Map<String, Object> queryCountForReport(Date begin, Date endDate) {
        return sysLogInfoDao.queryCountForReport(begin, endDate);
    }

    /**
     * 按天来查询日志的数据
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 返回查询结果
     */

    public Map<String, Object> queryLogInfoList(Date startDate,
                                                Date endDate) {
        Date start = DateUtils.getStartOfDay(startDate), end = DateUtils.getEndOfDay(endDate);
        return sysLogInfoDao.queryLogInfoList(start, end);
    }

    /**
     * 按年月来查询日志数据
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 返回查询结果
     */

    public Map<String, Object> queryLogInfoListByYearMonth(
            Date startDate, Date endDate) {
        Date start = DateUtils.getStartDayOfMonth(startDate), end = DateUtils.getEndDayOfMonth(endDate);
        return sysLogInfoDao.queryLogInfoListByYearMonth(start, end);
    }

    /**
     * 按年来查询日志数据
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 返回查询结果
     */

    public Map<String, Object> queryLogInfoListByYear(Date startDate,
                                                      Date endDate) {
        Date start = DateUtils.getStartDayOfYear(startDate), end = DateUtils.getEndDayOfYear(endDate);
        return sysLogInfoDao.queryLogInfoListByYear(start, end);
    }

    @Transactional
    public void saveLogEvent(SysLogInfo logInfo, List<SysLogProperty> sysLogPropertys, List<SysLogErrorMessage> logErrorMessages) {
        sysLogInfoRepository.save(logInfo);
        if (ValidatorUtils.isArrayNotEmpty(sysLogPropertys)) {
            for (SysLogProperty sysLogProperty : sysLogPropertys) {
                sysLogProperty.setId(logInfo.getId());
            }
            sysLogPropertyRepository.save(sysLogPropertys);
        }
        if (ValidatorUtils.isArrayNotEmpty(logErrorMessages)) {
            for (SysLogErrorMessage sysLogErrorMessage : logErrorMessages) {
                sysLogErrorMessage.setEventId(logInfo.getId());
            }
            sysLogErrorMessageRepository.save(logErrorMessages);
        }
    }

}
